package com.aaa.web.util;

import com.aaa.web.entity.Emp;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

public class BaseDao {
//    private final static String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
//    private final static String URL = "jdbc:mysql://localhost:3306/db_qy164?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai";
//    private final static String USER_NAME = "root";
//    private final static String PASSWORD = "root";
    private static DataSource dataSource;

    /**
     * 静态匿名块   类被加载时执行，并且只执行一次
     */
    static {
        try {
            //读取配置文件
            InputStream inputStream = BaseDao.class.getResourceAsStream("/db.properties");
            //实例化properties
            Properties properties = new Properties();
            //加载流，初始化properties
            properties.load(inputStream);
            //使用data工厂类创建dataSource对象
            dataSource = DruidDataSourceFactory.createDataSource(properties);
            //加载驱动类
            Class.forName(properties.getProperty("driverClassName"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Connection
     * @return
     */
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * 设置参数
     * @param preparedStatement
     * @param paramsArray
     */
    public static  void  setParams(PreparedStatement preparedStatement, Object[] paramsArray) throws SQLException {
        //判断参数数组是否为null
        if(paramsArray==null||paramsArray.length==0){
            // System.out.println("参数数组为空错误！");
            return;
        }
        //循环遍历
        for (int i = 0; i < paramsArray.length; i++) {
            //因为preparedStatement设置参数下标从1开始，循环数组的下标从0开始
            preparedStatement.setObject(i+1,paramsArray[i]);
        }
    }

    /**
     * 更新方法
     * @param sql  要执行更新的语句
     * @param params  需要的参数
     * @return
     */
    public static  int  executeUpdate(String sql,Object[] params){
        //调用封装方法获取Connection
        Connection connection = getConnection();
        PreparedStatement preparedStatement = null;
        //定义返回值
        int resultNum = 0;
        try {
            //获取preparedStatement语句执行对象，并传入sql语句
            preparedStatement = connection.prepareStatement(sql);
            //调用封装方法获取参数
            setParams(preparedStatement,params);
            //执行更新,并返回执行成功条数
            //return preparedStatement.executeUpdate();
            resultNum = preparedStatement.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            closeAll(connection,preparedStatement,null);
        }
        //return 0;
        return resultNum;
    }


    /**
     * 使用反射，查询任意对象集合
     * <A>定义泛型 List<A> A类型的集合
     * @param sql
     * @param aClass
     * @param params
     * @param <A>
     * @return
     */
    public static <A> List<A> executeQueryA(String sql,Class<A> aClass,Object... params){
        //调用封装方法获取Connection对象
        Connection connection = getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        //获取语句执行对象，并执行语句
        try {
            preparedStatement = connection.prepareStatement(sql);
            //设置参数
            setParams(preparedStatement,params);
            //执行查询
            resultSet = preparedStatement.executeQuery();
            //获取原数据对象
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取执行语句的总列数
            int columnCount = metaData.getColumnCount();
            //sql = select dept_no,dept_name,loc from dept;
            //定义返回集合  A = Dept
            List<A> aList = new ArrayList<>();
            //定义  A  的对象
            A a = null;
            //循环结果
            while (resultSet.next()){
                //每一行数据
                // 第1行 11     财务部1   郑州1
                // 第2行 112    市场1部   开封1
                // 第3行 113    市场2部   开封2
                //  ....
                a = aClass.newInstance();
                //循环每一行的每一列
                for (int i = 1; i <= columnCount; i++) {
                    //ColumnName 第一次 dept_no
                    String columnName = metaData.getColumnName(i);
                    //columnName 是带有下划线的 但属性名称中没有（多个单词中是驼峰状的）
                    Field declaredField = aClass.getDeclaredField(convertColumnNameToFieldName(columnName));
                    //设置可访问
                    declaredField.setAccessible(true);
                    declaredField.set(a,resultSet.getObject(i));
                }
                aList.add(a);
            }
            return aList;
        } catch (Exception e) {
             e.printStackTrace();
        } finally {
            closeAll(connection,preparedStatement,resultSet);
        }
        return null;
    }

    /**
     * 转换方法
     * @param columnName
     * @return
     */
    private static String convertColumnNameToFieldName(String columnName){
        //columnName = log_goods_type_remark -> logGoodsTypeRemark
        //判断列名称中是否含有_ 如果没有，直接返回
        if (columnName.indexOf("_")==-1){
            return columnName;
        }
        String[] columnNameArray = columnName.split("_");
        //实例化StringBuilder对象     columnNameArray[0] = log
        StringBuilder stringBuilder = new StringBuilder(columnNameArray[0]);
        //循环 第一个元素已经被加入到字符串拼接中  从1开始循环
        for (int i = 1; i < columnNameArray.length; i++) {
            //第一次 goods 第二次 type...
            String columnNameItem = columnNameArray[i];
            //第一次
            //columnNameItem = goods  substring(0,1)=g   toUpperCase() G
            //columnNameItem = goods  columnNameItem.substring(1)=oods
            // + Goods
            //第二次
            //columnNameItem = type  substring(0,1)=t   toUpperCase() T
            //columnNameItem = type  columnNameItem.substring(1)=yep
            // + Type
            stringBuilder.append(columnNameItem.substring(0, 1).toUpperCase()+columnNameItem.substring(1));
        }
        //stringBuilder = log
        return stringBuilder.toString();
    }



    /**
     * 执行查询
     *
     * @param sql    要执行的语句
     * @param params 需要的参数  ... jdk5的新特性   相当于数组 但是数组输入必须参数，没有参数必须传null  使用...没有参数可以不传
     * @return
     */
    //public static List<Map>  executeQuery(String sql,Object... params,int... i){ //不能含有多个...
    //public static List<Map>  executeQuery(String sql,Object... params,int i){  //参数...必须放到最后
    public static List<Map> executeQuery(String sql, Object... params){
        //调用封装类获取Connection
        Connection connection = getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        //定义返回结果集
        List<Map> returnMapList = new ArrayList<>();
        try {
            //获取语句执行对象，并传入sql
            preparedStatement = connection.prepareStatement(sql);
            //调用封装方法设置参数
            setParams(preparedStatement,params);
            //执行查询并返回结果集
            resultSet = preparedStatement.executeQuery();

            // 通过resultSet获取元数据对象
            ResultSetMetaData metaData = resultSet.getMetaData();
            //sql = select dept_no,dept_name,loc from tb_dept    columnCount = 3
            //sql = select `emp_id`, `emp_name`, `sex`, `phone_num`, `province`, `hire_date`, `dept_no`, `salary`, `password` from tb_dept    columnCount = 9
            //sql = select `emp_id`, `emp_name`, `sex`, `phone_num` from tb_goods   columnCount = 4
            //  ....    ....
            //sql = select *  from tables;    columnCount = count(column)
            // 动态获取执行语句的列的数量
            int columnCount = metaData.getColumnCount();

            //定义Map集合
            Map map = null;

            //循环结果集
            while (resultSet.next()){
                //每循环一次都要实例化一个Map  把当前行的内容放入里面
                map = new HashMap();
                // dept_no dept_name loc
                // 第1次 11     财务部1   郑州1
                // 第2次 112    市场1部   开封1
                // 第3次 113    市场2部   开封2
                //  ....
                //每循环一次，获取一行数据
                /* map.put(列名称, resultSet.getObject(1));
                 map.put(列名称, resultSet.getObject(2));
                 map.put(列名称, resultSet.getObject(3));
                 .....*/
                //循环每行数据的列
                for (int i = 1; i <= columnCount; i++) {
                    //每行列   第1次  dept_no   11
                    //          第2次  dept_name   财务部1
                    //          第3次  loc   郑州1
                    //根据下标获取列的名称
                    String columnName = metaData.getColumnName(i);
                    //根据下标获取列的数据
                    Object columnValue = resultSet.getObject(i);
                    //把列名称和值存入map
                    map.put(columnName,columnValue);
                }
                //把每行map放入返回集合
                returnMapList.add(map);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            closeAll(connection,preparedStatement,resultSet);
        }
        return returnMapList;
    }

    /**
     * 关闭方法   后打开的先关闭
     * @param connection
     * @param statement
     * @param resultSet
     */
    public static void closeAll(Connection connection,Statement statement,ResultSet resultSet){
        try {
            if(resultSet!=null){
                resultSet.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if(statement!=null){
                statement.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if(connection!=null){
                connection.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
